﻿//------------------------------------------------------------
// Author: 烟雨迷离半世殇
// Mail: 1778139321@qq.com
// Data: 2019年12月30日 20:50:09
//------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Reflection;

namespace NKG_MVVM_UI
{
    /// <summary>
    /// 用以绑定BindableProperty的改变事件
    /// 因为绑定对象的改变势必会导致一个旧VM函数的Remove，和一个新VM函数的Add
    /// 所以这里做了一下封装
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class PropertyBinder<T> where T : AViewModel
    {
        /// <summary>
        /// 绑定处理函数
        /// </summary>
        /// <param name="viewmodel"></param>
        private delegate void BindHandler(T viewmodel);

        /// <summary>
        /// 解绑处理函数
        /// </summary>
        /// <param name="viewmodel"></param>
        private delegate void UnBindHandler(T viewmodel);

        /// <summary>
        /// 管理绑定函数集合
        /// </summary>
        private readonly List<BindHandler> _binders = new List<BindHandler>();
        
        /// <summary>
        /// 管理解绑函数集合
        /// </summary>
        private readonly List<UnBindHandler> _unbinders = new List<UnBindHandler>();

        /// <summary>
        /// 新增属性绑定
        /// </summary>
        /// <param name="name">BindableProperty属性的name</param>
        /// <param name="valueChangedHandler">目标函数</param>
        /// <typeparam name="TProperty">必须是BindableProperty对象的泛型约束</typeparam>
        /// <exception cref="Exception">当BindableProperty属性的name不存在时报出的异常</exception>
        public void Add<TProperty>(string name, BindableProperty<TProperty>.ValueChangedHandler valueChangedHandler)
        {
            var fieldInfo = typeof(T).GetField(name, BindingFlags.Instance | BindingFlags.Public);
            if (fieldInfo == null)
            {
                throw new Exception(string.Format("Unable to find bindableproperty field '{0}.{1}'", typeof(T).Name,
                    name));
            }
            
            //管理绑定函数集合新增
            _binders.Add(viewmodel =>
            {
                GetPropertyValue<TProperty>(name, viewmodel, fieldInfo).OnValueChanged += valueChangedHandler;
            });

            //管理解绑函数集合移除
            _unbinders.Add(viewModel =>
            {
                GetPropertyValue<TProperty>(name, viewModel, fieldInfo).OnValueChanged -= valueChangedHandler;
            });
        }

        /// <summary>
        /// 获取目标属性值
        /// </summary>
        /// <param name="name">属性name</param>
        /// <param name="viewModel">目标VM</param>
        /// <param name="fieldInfo">反射字段信息</param>
        /// <typeparam name="TProperty">必须是BindableProperty对象的泛型约束</typeparam>
        /// <returns></returns>
        /// <exception cref="Exception">当BindableProperty属性的name不存在时报出的异常</exception>
        private BindableProperty<TProperty> GetPropertyValue<TProperty>(string name, T viewModel, FieldInfo fieldInfo)
        {
            var value = fieldInfo.GetValue(viewModel);
            BindableProperty<TProperty> bindableProperty = value as BindableProperty<TProperty>;
            if (bindableProperty == null)
            {
                throw new Exception(string.Format("Illegal bindableproperty field '{0}.{1}' ", typeof(T).Name, name));
            }

            return bindableProperty;
        }

        /// <summary>
        /// 绑定VM
        /// </summary>
        /// <param name="viewmodel"></param>
        public void Bind(T viewmodel)
        {
            if (viewmodel != null)
            {
                for (int i = 0; i < _binders.Count; i++)
                {
                    _binders[i](viewmodel);
                }
            }
        }

        /// <summary>
        /// 解绑VM
        /// </summary>
        /// <param name="viewmodel"></param>
        public void Unbind(T viewmodel)
        {
            if (viewmodel != null)
            {
                for (int i = 0; i < _unbinders.Count; i++)
                {
                    _unbinders[i](viewmodel);
                }
            }
        }
    }
}